package com.sneakxy.mybatis.commons.repository.support;

import java.util.List;

import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.repository.query.ResultProcessor;

import com.sneakxy.mybatis.commons.orm.MybatisEntityManager;
import com.sneakxy.mybatis.commons.repository.query.MybatisQueryMethod;
import com.sneakxy.mybatis.commons.utils.MybatisUtils;

/**
 * @author 潜行的青衣
 */
public class MybatisXmlMapperRepositoryQuery extends AbstractMybatisRepositoryQuery {
	
	private String pageCountQueryId;

	public MybatisXmlMapperRepositoryQuery(
			MybatisEntityManager entityManager,
			MybatisQueryMethod queryMethod) {
		super(entityManager, queryMethod);
	}
	
	/* (non-Javadoc)
	 * @see org.springframework.data.repository.query.RepositoryQuery#execute(java.lang.Object[])
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Override
	public Object execute(Object[] parameters) {
		ResultProcessor processor = this.getQueryMethod().getResultProcessor();
		SqlSessionTemplate template = this.getEntityManager().getSqlSessionTemplate();
		String statement = this.getEntityManager().getNamespacedId(this.getMethod().getName());
		MappedStatement mappedStatement = this.getEntityManager().getConfiguration().getMappedStatement(statement);
		SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
		Object parameterObject = this.createParameterObject(parameters, false);
		if(sqlCommandType == SqlCommandType.SELECT) {
			if(this.getQueryMethod().isCollectionQuery()) {
				return template.selectList(statement, parameterObject);
			} else if(this.getQueryMethod().isPageQuery() || this.getQueryMethod().isSliceQuery()) {
				List<Object> content = template.selectList(statement, parameterObject);
				Long total = template.selectOne(this.getPageCountQueryId(), createParameterObject(parameters, true));
				return new PageImpl(content, MybatisUtils.getPageable(parameters), total);
			} else {
				Object result = template.selectOne(statement, parameterObject);
				return processor.processResult(result);
			}
		} else if(sqlCommandType == SqlCommandType.INSERT) {
			return processor.processResult(template.insert(statement, parameterObject));
		} else if(sqlCommandType == SqlCommandType.UPDATE) {
			return processor.processResult(template.update(statement, parameterObject));
		} else if(sqlCommandType == SqlCommandType.DELETE) {
			return processor.processResult(template.delete(statement, parameterObject));
		}
		if(this.getQueryMethod().getReturnedObjectType().isPrimitive()) {
			return processor.processResult(0);
		}
		return processor.processResult(null);
	}

	public String getPageCountQueryId() {
		return pageCountQueryId;
	}

	/* (non-Javadoc)
	 * @see com.sneakxy.mybatis.commons.repository.support.AbstractMybatisRepositoryQuery#doCreatePageCountQuery()
	 */
	@Override
	protected void doCreatePageCountQuery() {
		StringBuilder idBuilder = new StringBuilder()
				.append("count_").append(this.getQueryMethod().getName());
		String resultId = idBuilder.toString();
		this.pageCountQueryId = this.getEntityManager().getNamespacedId(resultId);
	}

}
